package org.teremail.mailbox;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.google.common.base.Joiner;

/**
 * Representation of hierachical path.  Takes a path as a '/' delimited
 * string.
 * 
 */
public final class Path {

    private final List<String> parts;
    public final static String INBOX_NAME = "INBOX";
    public final static Path INBOX = path(INBOX_NAME);
    @SuppressWarnings("unchecked")
    public final static Path ROOT = new Path(Collections.EMPTY_LIST);

    private Path(List<String> parts) {
        this.parts = Collections.unmodifiableList(parts);
    }
    
    public boolean isChildOf(Path other) {
        if (parts.size() < other.parts.size()) {
            return false;
        }
        
        Iterator<String> thisIt = parts.iterator();
        Iterator<String> otherIt = other.parts.iterator();
        while (otherIt.hasNext() && thisIt.hasNext()) {
            if (!thisIt.next().equals(otherIt.next())) {
                return false;
            }
        }
        
        return true;
    }

    public List<String> getParts() {
        return parts;
    }
    
    /**
     * Compares the paths for equality, are equal iff the parts are the same.
     */
    public boolean equals(Object o) {
        if (o == null || !(o instanceof Path)) {
            return false;
        }
        
        Path other = (Path) o;
        
        if (parts.size() != other.parts.size()) {
            return false;
        }
        
        Iterator<String> thisIt = parts.iterator();
        Iterator<String> otherIt = other.parts.iterator();
        while (otherIt.hasNext() && thisIt.hasNext()) {
            if (!thisIt.next().equals(otherIt.next())) {
                return false;
            }
        }
        
        return true;
    }
    
    public int hashCode() {
        int code = 0;
        for (String part : parts) {
            code += part.hashCode();
        }
        return code;
    }
    
    public String last() {
        return parts.get(parts.size() - 1);
    }

    @Override
    public String toString() {
        return Joiner.on("/").join(parts);
    }

    public Path replace(Path target, Path replacement) {
        Path head = new Path(parts.subList(0, target.parts.size()));
        Path result;
        if (head.equals(target)) {
            @SuppressWarnings("unchecked")
            List<String> newParts = Lists.concat(replacement.parts, 
                    parts.subList(target.parts.size(), parts.size()));
            result = new Path(newParts);
        } else {
            result = this;
        }
        return result;
    }
    
    /**
     * Static create method.  Handles renaming inbox to upper case.
     * 
     * @param pathStr
     * @return
     */
    public static Path path(String pathStr) {
        
        String[] pathArr = pathStr.split("/");
        if (INBOX_NAME.equalsIgnoreCase(pathArr[0])) {
            pathArr[0] = INBOX_NAME;
        }
        
        return new Path(Arrays.asList(pathArr));
    }

    public boolean isInbox() {
        return INBOX_NAME.equals(parts.get(0));
    }

    
}
